unit Rule_HHV;

interface

uses
  BaseRule,
  BaseRuleData;

type
  TRule_HHV_I = class(TBaseRuleI64)
  protected
    fParamN: Word;
    fInt64Ret: PArrayInt64;
    function GetHHVValueI(AIndex: integer): int64;
    function GetParamN: Word;
    procedure SetParamN(const Value: Word);
    procedure ComputeInt64;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure Execute; override;
    property ValueI[AIndex: integer]: int64 read GetHHVValueI;
    property ParamN: Word read GetParamN write SetParamN;
  end;
            
  TRule_HHV_F = class(TBaseRuleF)
  protected
    fParamN: Word;
    fFloatRet: PArrayDouble;
    function GetHHVValueF(AIndex: integer): double;
    function GetParamN: Word;
    procedure SetParamN(const Value: Word);
    procedure ComputeFloat;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure Execute; override;
    property ValueF[AIndex: integer]: double read GetHHVValueF;
    property ParamN: Word read GetParamN write SetParamN;
  end;
          
implementation

{ TRule_HHV }

constructor TRule_HHV_I.Create;
begin
  inherited;
  fParamN := 20;        
  fInt64Ret := nil;
end;
                    
constructor TRule_HHV_F.Create;
begin
  inherited;
  fParamN := 20;        
  fFloatRet := nil;
end;

destructor TRule_HHV_I.Destroy;
begin
  CheckInArrayInt64(fInt64Ret);
  inherited;
end;
           
destructor TRule_HHV_F.Destroy;
begin
  CheckInArrayDouble(fFloatRet);  
  inherited;
end;

procedure TRule_HHV_I.Execute;
begin
  if Assigned(OnGetDataLength) then
  begin
    fBaseRuleData.DataLength := OnGetDataLength;
    ComputeInt64;
  end;
end;

procedure TRule_HHV_F.Execute;
begin
  if Assigned(OnGetDataLength) then
  begin
    fBaseRuleData.DataLength := OnGetDataLength;
    ComputeFloat;
  end;
end;

procedure TRule_HHV_I.ComputeInt64;
var
  tmpInt64_Meta: PArrayInt64;
  i: integer;
  tmpCounter: integer;
  tmpValue: Int64;
begin
  if Assigned(OnGetDataI) then
  begin                 
    if fInt64Ret = nil then
      fInt64Ret := CheckOutArrayInt64;
    tmpInt64_Meta := CheckOutArrayInt64;
    try
      SetArrayInt64Length(fInt64Ret, fBaseRuleData.DataLength);
      SetArrayInt64Length(tmpInt64_Meta, fBaseRuleData.DataLength);
      for i := 0 to fBaseRuleData.DataLength - 1 do
      begin
        tmpInt64_Meta.Value[i] := OnGetDataI(i);
        tmpValue := tmpInt64_Meta.Value[i];
        tmpCounter := fParamN - 1;
        while tmpCounter > 0 do
        begin
          if i > tmpCounter - 1 then
          begin
            if tmpValue < tmpInt64_Meta.Value[i - tmpCounter] then
            begin
              tmpValue := tmpInt64_Meta.Value[i - tmpCounter];
            end;
          end;
          Dec(tmpCounter);
        end;         
        SetArrayInt64Value(fInt64Ret, i, tmpValue);
      end;
    finally
      CheckInArrayInt64(tmpInt64_Meta);
    end;
  end;
end;

procedure TRule_HHV_F.ComputeFloat;
var
  tmpFloat_Meta: PArrayDouble;
  i: integer;
  tmpCounter: integer;   
  tmpValue: double;
begin
  if Assigned(OnGetDataF) then
  begin                      
    if fFloatRet = nil then
      fFloatRet := CheckOutArrayDouble;
    tmpFloat_Meta := CheckOutArrayDouble;
    try
      SetArrayDoubleLength(fFloatRet, fBaseRuleData.DataLength);
      SetArrayDoubleLength(tmpFloat_Meta, fBaseRuleData.DataLength);
      for i := 0 to fBaseRuleData.DataLength - 1 do
      begin
        tmpFloat_Meta.Value[i] := OnGetDataF(i);
        tmpValue := tmpFloat_Meta.Value[i];
        tmpCounter := fParamN - 1;
        while tmpCounter > 0 do
        begin
          if i > tmpCounter - 1 then
          begin
            if tmpValue < tmpFloat_Meta.Value[i - tmpCounter] then
            begin
              tmpValue := tmpFloat_Meta.Value[i - tmpCounter];
            end;
          end;
          Dec(tmpCounter);
        end;         
        SetArrayDoubleValue(fFloatRet, i, tmpValue);
      end;
    finally
      CheckInArrayDouble(tmpFloat_Meta);
    end;
  end;
end;

function TRule_HHV_I.GetParamN: Word;
begin
  Result := fParamN;
end;

function TRule_HHV_F.GetParamN: Word;
begin
  Result := fParamN;
end;

procedure TRule_HHV_I.SetParamN(const Value: Word);
begin
  if Value > 0 then
    fParamN := Value;
end;

procedure TRule_HHV_F.SetParamN(const Value: Word);
begin
  if Value > 0 then
    fParamN := Value;
end;
                   
function TRule_HHV_I.GetHHVValueI(AIndex: integer): int64;
begin
  Result := 0;
  if fBaseRuleData.DataType = dtInt64 then
  begin            
    if fInt64Ret <> nil then
    begin
      Result := GetArrayInt64Value(fInt64Ret, AIndex);
    end;
  end;
end;

function TRule_HHV_F.GetHHVValueF(AIndex: integer): double;
begin
  Result := 0;
  if fBaseRuleData.DataType = dtDouble then
  begin               
    if fFloatRet <> nil then
    begin
      Result := GetArrayDoubleValue(fFloatRet, AIndex);
    end;
  end;
end;

end.
